/*     */ package com.zimbra.cs.mailclient;
/*     */ 
/*     */ import com.zimbra.common.util.Log;
/*     */ import com.zimbra.cs.mailclient.auth.Authenticator;
/*     */ import com.zimbra.cs.mailclient.auth.AuthenticatorFactory;
/*     */ import com.zimbra.cs.mailclient.util.Ascii;
/*     */ import java.io.BufferedInputStream;
/*     */ import java.io.BufferedOutputStream;
/*     */ import java.io.IOException;
/*     */ import java.io.InputStream;
/*     */ import java.io.OutputStream;
/*     */ import java.net.InetAddress;
/*     */ import java.net.InetSocketAddress;
/*     */ import java.net.Socket;
/*     */ import java.net.SocketException;
/*     */ import javax.net.SocketFactory;
/*     */ import javax.net.ssl.SSLSocket;
/*     */ import javax.net.ssl.SSLSocketFactory;
/*     */ import javax.security.auth.login.LoginException;
/*     */ import javax.security.sasl.SaslException;
/*     */ import org.apache.commons.codec.binary.Base64;
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ public abstract class MailConnection
/*     */ {
/*     */   protected MailConfig config;
/*     */   protected Socket socket;
/*     */   protected Authenticator authenticator;
/*     */   protected MailInputStream mailIn;
/*     */   protected MailOutputStream mailOut;
/*  50 */   protected State state = State.CLOSED;
/*     */   protected String greeting;
/*     */   
/*     */   protected static enum State
/*     */   {
/*  55 */     CLOSED,  NOT_AUTHENTICATED,  AUTHENTICATED,  SELECTED,  LOGOUT;
/*     */     
/*     */ 
/*     */     private State() {}
/*     */   }
/*     */   
/*     */ 
/*     */   protected MailConnection(MailConfig config)
/*     */   {
/*  64 */     this.config = config;
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   public synchronized void connect()
/*     */     throws IOException
/*     */   {
/*  74 */     if (!isClosed()) return;
/*     */     try {
/*  76 */       this.socket = newSocket();
/*  77 */       initStreams(new BufferedInputStream(this.socket.getInputStream()), new BufferedOutputStream(this.socket.getOutputStream()));
/*     */       
/*  79 */       processGreeting();
/*  80 */       switch (this.config.getSecurity()) {
/*     */       case TLS: 
/*  82 */         startTls();
/*  83 */         break;
/*     */       case TLS_IF_AVAILABLE: 
/*     */         try {
/*  86 */           startTls();
/*     */         } catch (CommandFailedException e) {
/*  88 */           getLogger().debug("STARTTLS failed", e);
/*     */         }
/*     */       }
/*     */     }
/*     */     catch (IOException e) {
/*  93 */       close();
/*  94 */       throw e;
/*     */     }
/*     */   }
/*     */   
/*     */   protected void startTls() throws IOException {
/*  99 */     checkState(State.NOT_AUTHENTICATED);
/* 100 */     sendStartTls();
/* 101 */     SSLSocket sock = newSSLSocket(this.socket);
/* 102 */     sock.startHandshake();
/* 103 */     initStreams(sock.getInputStream(), sock.getOutputStream());
/*     */   }
/*     */   
/*     */   private void initStreams(InputStream is, OutputStream os) {
/* 107 */     this.mailIn = newMailInputStream(is);
/* 108 */     this.mailOut = newMailOutputStream(os);
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   protected abstract void processGreeting()
/*     */     throws IOException;
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   protected abstract void sendLogin(String paramString1, String paramString2)
/*     */     throws IOException;
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   protected abstract void sendAuthenticate(boolean paramBoolean)
/*     */     throws IOException;
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   protected abstract void sendStartTls()
/*     */     throws IOException;
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   protected abstract MailInputStream newMailInputStream(InputStream paramInputStream);
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   protected abstract MailOutputStream newMailOutputStream(OutputStream paramOutputStream);
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   public final Log getLogger()
/*     */   {
/* 175 */     return this.config.getLogger();
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   public abstract void logout()
/*     */     throws IOException;
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   public synchronized void login(String pass)
/*     */     throws IOException
/*     */   {
/* 194 */     if (pass == null) throw new NullPointerException("password");
/* 195 */     checkState(State.NOT_AUTHENTICATED);
/* 196 */     String user = this.config.getAuthenticationId();
/* 197 */     if (user == null) {
/* 198 */       throw new IllegalStateException("Authentication id missing");
/*     */     }
/* 200 */     sendLogin(user, pass);
/* 201 */     setState(State.AUTHENTICATED);
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   public synchronized void authenticate(String pass)
/*     */     throws LoginException, IOException
/*     */   {
/* 217 */     String mech = this.config.getMechanism();
/* 218 */     if ((mech == null) || (mech.equalsIgnoreCase("LOGIN"))) {
/* 219 */       login(pass);
/*     */     } else {
/* 221 */       authenticate(newAuthenticator(pass));
/*     */     }
/*     */   }
/*     */   
/*     */   public synchronized void authenticate(Authenticator auth) throws IOException {
/* 226 */     this.authenticator = auth;
/* 227 */     checkState(State.NOT_AUTHENTICATED);
/* 228 */     sendAuthenticate(false);
/* 229 */     if (this.authenticator.isEncryptionEnabled()) {
/* 230 */       initStreams(this.authenticator.unwrap(this.socket.getInputStream()), this.authenticator.wrap(this.socket.getOutputStream()));
/*     */     }
/*     */     
/* 233 */     setState(State.AUTHENTICATED);
/*     */   }
/*     */   
/*     */   private Authenticator newAuthenticator(String pass) throws LoginException, SaslException
/*     */   {
/* 238 */     AuthenticatorFactory af = this.config.getAuthenticatorFactory();
/* 239 */     if (af == null) {
/* 240 */       af = AuthenticatorFactory.getDefault();
/*     */     }
/* 242 */     return af.newAuthenticator(this.config, pass);
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   public String getGreeting()
/*     */   {
/* 251 */     return this.greeting;
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   protected void processContinuation(String s)
/*     */     throws IOException
/*     */   {
/* 263 */     byte[] decoded = Base64.decodeBase64(Ascii.getBytes(s));
/* 264 */     byte[] request = this.authenticator.evaluateChallenge(decoded);
/* 265 */     String data = Ascii.toString(Base64.encodeBase64(request));
/* 266 */     this.mailOut.writeLine(data);
/* 267 */     this.mailOut.flush();
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   public String getNegotiatedQop()
/*     */   {
/* 278 */     return this.authenticator != null ? this.authenticator.getNegotiatedProperty("javax.security.sasl.qop") : null;
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   public MailInputStream getInputStream()
/*     */   {
/* 288 */     return this.mailIn;
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   public MailOutputStream getOutputStream()
/*     */   {
/* 297 */     return this.mailOut;
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   public MailConfig getConfig()
/*     */   {
/* 306 */     return this.config;
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   public void setReadTimeout(int readTimeout)
/*     */     throws SocketException
/*     */   {
/* 317 */     int timeout = (int)Math.min(readTimeout * 1000L, 2147483647L);
/* 318 */     if ((this.socket != null) && (!isClosed())) {
/* 319 */       this.socket.setSoTimeout(timeout > 0 ? timeout : Integer.MAX_VALUE);
/*     */     }
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */   public synchronized boolean isClosed()
/*     */   {
/* 328 */     return this.state == State.CLOSED;
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   public synchronized boolean isAuthenticated()
/*     */   {
/* 337 */     return this.state == State.AUTHENTICATED;
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */   public synchronized boolean isLogout()
/*     */   {
/* 345 */     return this.state == State.LOGOUT;
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */   public synchronized boolean isSelected()
/*     */   {
/* 352 */     return this.state == State.SELECTED;
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   protected synchronized void setState(State state)
/*     */   {
/* 361 */     if (this.state != state) {
/* 362 */       getLogger().debug("setState: " + this.state + " -> " + state);
/* 363 */       this.state = state;
/*     */     }
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   protected void checkState(State expected)
/*     */   {
/* 375 */     if (this.state != expected) {
/* 376 */       throw new IllegalStateException("Operation not supported in " + this.state + " state");
/*     */     }
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   public synchronized void close()
/*     */   {
/* 386 */     if (isClosed()) return;
/* 387 */     setState(State.CLOSED);
/*     */     try {
/* 389 */       this.mailIn.close();
/*     */     }
/*     */     catch (IOException e) {}
/*     */     try
/*     */     {
/* 394 */       this.mailOut.close();
/*     */     }
/*     */     catch (IOException e) {}
/*     */     try
/*     */     {
/* 399 */       this.socket.close();
/*     */     } catch (IOException e) {
/* 401 */       getLogger().info("Error while closing connection", e);
/*     */     }
/* 403 */     if (this.authenticator != null) {
/*     */       try {
/* 405 */         this.authenticator.dispose();
/*     */       } catch (SaslException e) {
/* 407 */         getLogger().debug("Error while deleting authenticator", e);
/*     */       }
/*     */     }
/*     */   }
/*     */   
/*     */   private Socket newSocket() throws IOException {
/* 413 */     SocketFactory sf = this.config.getSecurity() != MailConfig.Security.SSL ? getSocketFactory() : getSSLSocketFactory();
/*     */     
/* 415 */     Socket sock = sf.createSocket();
/* 416 */     int connectTimeout = (int)Math.min(this.config.getConnectTimeout() * 1000L, 2147483647L);
/*     */     
/* 418 */     int readTimeout = (int)Math.min(this.config.getReadTimeout() * 1000L, 2147483647L);
/*     */     
/* 420 */     sock.setSoTimeout(readTimeout > 0 ? readTimeout : Integer.MAX_VALUE);
/* 421 */     sock.connect(new InetSocketAddress(this.config.getHost(), this.config.getPort()), connectTimeout > 0 ? connectTimeout : Integer.MAX_VALUE);
/*     */     
/* 423 */     return sock;
/*     */   }
/*     */   
/*     */   private SSLSocket newSSLSocket(Socket sock) throws IOException {
/* 427 */     return (SSLSocket)getSSLSocketFactory().createSocket(sock, sock.getInetAddress().getHostName(), sock.getPort(), false);
/*     */   }
/*     */   
/*     */   private SocketFactory getSocketFactory()
/*     */   {
/* 432 */     SocketFactory sf = this.config.getSocketFactory();
/* 433 */     return sf != null ? sf : SocketFactory.getDefault();
/*     */   }
/*     */   
/*     */   private SSLSocketFactory getSSLSocketFactory() {
/* 437 */     SSLSocketFactory ssf = this.config.getSSLSocketFactory();
/* 438 */     return ssf != null ? ssf : (SSLSocketFactory)SSLSocketFactory.getDefault();
/*     */   }
/*     */   
/*     */   public String toString()
/*     */   {
/* 443 */     return String.format("{host=%s,port=%d,type=%s,state=%s}", new Object[] { this.config.getHost(), Integer.valueOf(this.config.getPort()), this.config.getSecurity(), this.state });
/*     */   }
/*     */ }


/* Location:              /home/mint/zimbrastore.jar!/com/zimbra/cs/mailclient/MailConnection.class
 * Java compiler version: 7 (51.0)
 * JD-Core Version:       0.7.1
 */